#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string>
#include <cstring>
#include "Log.hpp"
#include "err.hpp"
const static int gbacklog = 32;//全连接队列的长度
class Sock
{
public: 
    static int Socket()
    {
        //1、创建监听socket套接字
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if(sock < 0)
        {
            LogMessage(FATAL, "create socket error");
            exit(SOCKET_ERR);
        }
        LogMessage(NORMAL,"create socket success: %d", sock);
        //地址复用
        int opt = 1;
        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        return sock;
    }

    static void Bind(int sock, int port)
    {
        //2、绑定端口号+ip地址
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_family = AF_INET;
        local.sin_port=htons(port);
        if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
        {
            LogMessage(FATAL, "bind socket error");
            exit(BIND_ERR);
        }
        LogMessage(NORMAL, "bind socket success");
    }

    static void Listen(int sock)
    {
        //3、设置监听状态
        if(-1 == listen(sock, gbacklog))
        {
            LogMessage(FATAL, "listen socket error");
            exit(LISTEN_ERR);
        }
        LogMessage(NORMAL, "listen socket success");
    }

    static int Accept(int listenSock, std::string *clientIp, uint16_t* clientPort)
    {
        //5、服务器获取客户端连接请求
        struct sockaddr_in peer;//输出型参数，拿到客户端的信息
        socklen_t len=sizeof(peer);
        int sock = accept(listenSock, (struct sockaddr*)&peer, &len);
        if(-1 == sock)      
        {
            LogMessage(ERROR, "accept error,next");
            *clientIp = nullptr;
            *clientPort = -1;
            return -1;
        }        
        else
        {
            LogMessage(NORMAL, "accept a new link success");
            //提取客户端ip和端口号
            *clientIp = inet_ntoa(peer.sin_addr);
            *clientPort = ntohs(peer.sin_port);
            return sock;
        }   
        
    }
};
